package com.atguigu.gmall.activity.receiver;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * @Author LEO
 * @Date 2021年12月25日 22:20
 */
@Component
public class SeckillReceiver {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsService seckillGoodsService;

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    //监听消息将秒杀商品放入缓存
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_1}
    ))
    public void importItemToRedis(Message message, Channel channel) throws IOException {
        // 查询当天的秒杀商品数据集合  当天，审核状态 剩余库存数
        QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<>();
        // 查询审核状态1 并且库存数量大于0，当天的商品
        queryWrapper.eq("status",1).gt("stock_count",0);
        // 如果精确到秒：涉及到商品展示：什么时候开始，什么时候结束
        queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
        List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(queryWrapper);
        // 将集合数据放入缓存中
        if (!CollectionUtils.isEmpty(seckillGoodsList)){
            for (SeckillGoods seckillGoods : seckillGoodsList) {
                // 将数据放入缓存  数据类型key
                String seckillKey= RedisConst.SECKILL_GOODS;
                //判断当前秒杀商品在缓存中是否存在，
                // 判断当前field 在这个key 中是否存在  field=skuId
               Boolean flag =  redisTemplate.boundHashOps(seckillKey).hasKey(seckillGoods.getSkuId().toString());
               // flag=true 表示有数据 不要插入数据
                if (flag){
                    continue;
                }
                // 第一种方式
                //redisTemplate.opsForHash().put(seckillKey,seckillGoods.getSkuId().toString(),seckillGoods);
                // 第二种方式
                redisTemplate.boundHashOps(seckillKey).put(seckillGoods.getSkuId().toString(),seckillGoods);
                // 如何控制库存超卖，将商品的库存数量放入缓存
                for (Integer i = 0; i < seckillGoods.getStockCount(); i++) {
                    // RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId()
                    String key  =  RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId();
                    // key = seckill:stock:skuId
                    // value =skuId seckillGoods.getSkuId().toString()
//                    redisTemplate.opsForList().leftPush(key,seckillGoods.getSkuId().toString());
                    redisTemplate.boundListOps(seckillKey).leftPush(seckillGoods.getSkuId().toString());
                }
                // 状态位初始化 1  skuId:1  46:1
                redisTemplate.convertAndSend("seckillpush", seckillGoods.getSkuId()+":1");
                //
            }
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    //监听事件
    /**
     * 秒杀用户加入队列
     *
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER, durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER, type = ExchangeTypes.DIRECT, durable = "true"),
            key = {MqConst.ROUTING_SECKILL_USER}
    ))
    public void seckill(UserRecode userRecode, Message message, Channel channel) throws IOException {
        if (null != userRecode) {
            //Log.info("paySuccess:"+ JSONObject.toJSONString(userRecode));
            //预下单
            seckillGoodsService.seckillOrder(userRecode.getSkuId(), userRecode.getUserId());

            //手动确认收到消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    /**
     * 秒杀结束清空缓存
     *
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_18, durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK, type = ExchangeTypes.DIRECT, durable = "true"),
            key = {MqConst.ROUTING_TASK_18}
    ))
    public void clearRedis(Message message, Channel channel) throws IOException {

        //活动结束清空缓存
        QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 1);
        queryWrapper.le("end_time", new Date());
        List<SeckillGoods> list = seckillGoodsMapper.selectList(queryWrapper);
        //清空缓存
        for (SeckillGoods seckillGoods : list) {
            // 如果有多个秒杀商品则使用以下删除方式
//            redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).delete(seckillGoods.getSkuId());
            //删除库存 seckill:stock:skuId  seckill:stock:46
            redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX + seckillGoods.getSkuId());
        }
        // 秒杀商品只有一个
        redisTemplate.delete(RedisConst.SECKILL_GOODS);
        // seckill:orders 为啥要删除
        redisTemplate.delete(RedisConst.SECKILL_ORDERS);
        //删除真正的订单
        redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);
        //将状态更新为结束
        SeckillGoods seckillGoodsUp = new SeckillGoods();
        seckillGoodsUp.setStatus("2");
        seckillGoodsMapper.update(seckillGoodsUp, queryWrapper);
        // 手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}
